home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / svgakt50.zip / SRC / SVGAKIT / SVGA.ASM < prev    next >
Assembly Source File  |  1994-08-23  |  63KB  |  2,206 lines

  1. ;****************************************************************************
  2. ;*
  3. ;*                              The SuperVGA Kit
  4. ;*
  5. ;*                  Copyright (C) 1994 SciTech Software
  6. ;*                          All rights reserved.
  7. ;*
  8. ;* Filename:    $RCSfile: svga.asm $
  9. ;* Version:     $Revision: 1.1 $
  10. ;*
  11. ;* Language:    80386 Assembler
  12. ;* Environment: IBM PC Real Mode and 16/32 bit Protected Mode.
  13. ;*
  14. ;* Description: Assembly language support routines for the SuperVGA test
  15. ;*              library. All the code here assumes that the video memory
  16. ;*                selector has been cached in the FS selector before the
  17. ;*                code is called.
  18. ;*
  19. ;* $Id: svga.asm 1.1 1994/08/22 12:27:00 kjb release $
  20. ;*
  21. ;****************************************************************************
  22.  
  23.         IDEAL
  24.  
  25. INCLUDE "model.mac"             ; Memory model macros
  26.  
  27. header  svga                    ; Set up memory model
  28.  
  29. CRTC    EQU 3D4h                ; Port of CRTC registers
  30.  
  31.         $EXTRN  _maxx,UINT
  32.         $EXTRN  _maxy,UINT
  33.         $EXTRN  _maxcolor,ULONG
  34.         $EXTRN  _maxpage,UINT
  35.         $EXTRN  _bytesperline,USHORT
  36.         $EXTRN  _pagesize,ULONG
  37.         $EXTRN  _curBank,UINT
  38.         $EXTRN  _bankSwitch,ULONG
  39.         $EXTRN  _bankShift,UINT
  40.         $EXTRN  _writeBank,ULONG    ; Relocated write bank routine
  41.         $EXTRN  _readBank,ULONG     ; Relocated read bank routine
  42.         $EXTRN    _extendedflipping,BOOL
  43.  
  44. begdataseg    svga
  45.  
  46. originOffset    DW    ?                ; Offset of current page in buffer
  47. bankOffset        DW    ?                ; Bank offset in total video memory
  48.  
  49. enddataseg    svga
  50.  
  51. begcodeseg    svga
  52.  
  53. ;----------------------------------------------------------------------------
  54. ; int _setFS(unsigned sel)
  55. ;----------------------------------------------------------------------------
  56. ; Set the FS register to the specified selector value. This register is
  57. ; never changed, so we only ever need to do it once (to save time with
  58. ; expensive selector loads in protected mode).
  59. ;----------------------------------------------------------------------------
  60. procstart    __setFS
  61.  
  62.         ARG        sel:UINT
  63.  
  64.         push    _bp
  65.         mov        _bp,_sp
  66.         mov        _ax,[sel]
  67.         mov     cx,fs
  68.         mov        fs,ax
  69.         mov        ax,cx
  70.         pop        _bp
  71.         ret
  72.  
  73. procend        __setFS
  74.  
  75. ;----------------------------------------------------------------------------
  76. ; PixelAddr16    Determine buffer address of pixel in SVGA 16 color modes
  77. ;----------------------------------------------------------------------------
  78. ;
  79. ; Entry:        _AX    -    y-coordinate
  80. ;                _BX    -    x-coordinate
  81. ;
  82. ; Exit:            AH    -    bit mask
  83. ;                _BX    -    byte offset in buffer
  84. ;                CL    -    number of bits to shift left
  85. ;                _SI    -    64k bank number of the address
  86. ;                FS    -    video buffer segment
  87. ;
  88. ; Registers:    none.
  89. ;
  90. ;----------------------------------------------------------------------------
  91. PROC    PixelAddr16    near
  92.  
  93.         push    _dx                    ; Save DX
  94.         mul        [_bytesperline]        ; DX:AX := y * BytesPerLine
  95.         mov        cl,bl                ; CL := low-order byte of x
  96.  
  97.         shr        _bx,3                ; _BX := x/8
  98.         add        bx,ax
  99.         adc        dl,0                ; DL:_BX := y*BytesPerLine + x/8
  100.         add        bx,[originOffset]    ; _BX := byte offset in video buffer
  101.         adc        dl,[BYTE bankOffset]; DL := bank number
  102.         mov        _si,_dx                ; _SI := bank number
  103.  
  104.         mov        ah,1                ; AH := unshifted bit mask
  105.         and        cl,7                ; CL := x & 7
  106.         xor        cl,7                ; CL := # bits to shift left
  107.  
  108.         pop        _dx
  109.         ret
  110.  
  111. ENDP    PixelAddr16
  112.  
  113. ;----------------------------------------------------------------------------
  114. ; PixelAddr256    Determine buffer address of pixel in SVGA 256 color modes
  115. ;----------------------------------------------------------------------------
  116. ;
  117. ; Entry:        _AX    -    y-coordinate
  118. ;                _BX    -    x-coordinate
  119. ;
  120. ; Exit:            _BX    -    byte offset in buffer
  121. ;                _DX    -    64k bank number of the address
  122. ;                FS    -    video buffer segment
  123. ;
  124. ; Registers:    None.
  125. ;
  126. ;----------------------------------------------------------------------------
  127. PROC    PixelAddr256    near
  128.  
  129.         mul        [_bytesperline]        ; DX:AX := y * bytesperline
  130.         add        bx,ax
  131.         adc        dx,0                ; DX:_BX := y * BytesPerLine + x
  132.         add        bx,[originOffset]
  133.         adc        dl,[BYTE bankOffset]; DL := bank number
  134.         ret
  135.  
  136. ENDP    PixelAddr256
  137.  
  138. ;----------------------------------------------------------------------------
  139. ; PixelAddr32k    Determine buffer address of pixel in SVGA 32k color modes
  140. ;----------------------------------------------------------------------------
  141. ;
  142. ; Entry:        _AX    -    y-coordinate
  143. ;                _BX    -    x-coordinate
  144. ;
  145. ; Exit:            _BX    -    byte offset in buffer
  146. ;                _DX    -    64k bank number of the address
  147. ;                FS    -    video buffer segment
  148. ;
  149. ; Registers:    None.
  150. ;
  151. ;----------------------------------------------------------------------------
  152. PROC    PixelAddr32k    near
  153.  
  154.         mul        [_bytesperline]        ; DX:AX := y * bytesperline
  155.         shl        _bx,1
  156.         add        bx,ax
  157.         adc        dx,0                ; DX:BX := y * BytesPerLine + x * 2
  158.         add        bx,[originOffset]
  159.         adc        dl,[BYTE bankOffset]; DL := bank number
  160.         ret
  161.  
  162. ENDP    PixelAddr32k
  163.  
  164. ;----------------------------------------------------------------------------
  165. ; PixelAddr16m    Determine buffer address of pixel in SVGA 16m color modes
  166. ;----------------------------------------------------------------------------
  167. ;
  168. ; Entry:        _AX    -    y-coordinate
  169. ;                _BX    -    x-coordinate
  170. ;
  171. ; Exit:            _BX    -    byte offset in buffer
  172. ;                _DX    -    64k bank number of the address
  173. ;                FS    -    video buffer segment
  174. ;
  175. ; Registers:    None.
  176. ;
  177. ;----------------------------------------------------------------------------
  178. PROC    PixelAddr16m    near
  179.  
  180.         mul        [_bytesperline]        ; DX:AX := y * bytesperline
  181.         add        ax,bx
  182.         shl        _bx,1
  183.         add        bx,ax
  184.         adc        dx,0                ; DX:BX := y * BytesPerLine + x * 3
  185.         add        bx,[originOffset]
  186.         adc        dl,[BYTE bankOffset]; DL := bank number
  187.         ret
  188.  
  189. ENDP    PixelAddr16m
  190.  
  191. ;----------------------------------------------------------------------------
  192. ; PixelAddr4G    Determine buffer address of pixel in SVGA 32k color modes
  193. ;----------------------------------------------------------------------------
  194. ;
  195. ; Entry:        _AX    -    y-coordinate
  196. ;                _BX    -    x-coordinate
  197. ;
  198. ; Exit:            _BX    -    byte offset in buffer
  199. ;                _DX    -    64k bank number of the address
  200. ;                FS    -    video buffer segment
  201. ;
  202. ; Registers:    None.
  203. ;
  204. ;----------------------------------------------------------------------------
  205. PROC    PixelAddr4G    near
  206.  
  207.         mul        [_bytesperline]        ; DX:AX := y * bytesperline
  208.         shl        _bx,2
  209.         add        bx,ax
  210.         adc        dx,0                ; DX:BX := y * BytesPerLine + x * 2
  211.         add        bx,[originOffset]
  212.         adc        dl,[BYTE bankOffset]; DL := bank number
  213.         ret
  214.  
  215. ENDP    PixelAddr4G
  216.  
  217. ;----------------------------------------------------------------------------
  218. ; void clear16(long color)
  219. ;----------------------------------------------------------------------------
  220. ; Routine to clear the screen. Works even if the display contains more than
  221. ; one bank, so will work for 1024x768 and 1280x1024 video modes.
  222. ;----------------------------------------------------------------------------
  223. procstart   __clear16
  224.  
  225.         ARG        color:ULONG
  226.  
  227.         enter_c    0
  228.         push    es
  229.  
  230. ; Setup graphics controller
  231.  
  232.         mov     dx,3CEh             ; DX := Graphics Controller I/O port
  233.  
  234.         mov     ah,[BYTE color]        ; AH := Background color
  235.         xor     al,al               ; AL := 0 (Set/Reset register number)
  236.         out     dx,ax               ; load set/reset register
  237.  
  238.         mov     ax,0F01h            ; AH := 1111b (mask for Enable set/reset)
  239.                                     ; AL := 1 (enable Set/reset reg number)
  240.         out     dx,ax               ; load enable set/reset reg
  241.  
  242.         mov     _ax,[_maxy]
  243.         inc     _ax
  244.         mul     [_bytesperline]     ; DX:AX := number of bytes to fill
  245.         mov     bx,ax               ; BX := bytes in last bank to fill
  246.         mov     dh,dl               ; DH := number of full banks to fill
  247.  
  248.         mov        ax,fs
  249.         mov        es,ax
  250.         xor        _di,_di             ; ES:_DI -> video memory
  251.         add     di,[originOffset]
  252.         mov     ax,[bankOffset]     ; AX := starting bank number
  253.         cld                         ; Moves go up in memory
  254.  
  255.         or      dh,dh               ; More than one bank to fill?
  256.         jz      @@SingleBank        ; No, only fill a single bank
  257.  
  258. ; Fill all of the full 64k banks first
  259.  
  260. @@OuterLoop:
  261.         call    setBank
  262.         mov     _cx,4000h            ; Need to set 4000h double USHORTs per bank
  263.     rep stosd
  264.         xor        _di,_di
  265.         inc     al
  266.         dec     dh
  267.         jnz     @@OuterLoop
  268.  
  269. ; Now fill the last partial bank
  270.  
  271. @@SingleBank:
  272.         call    setBank
  273.         xor        _cx,_cx
  274.         mov     cx,bx
  275.         shr     _cx,2                ; _CX := number of double USHORTs to set
  276.     rep stosd
  277.  
  278. ; Restore graphics controller
  279.  
  280.         mov     dx,3CEh             ; DX := Graphics Controller I/O port
  281.         xor     ax,ax               ; AH := 0, AL := 0
  282.         out     dx,ax               ; Restore default Set/Reset register
  283.  
  284.         inc     ax                  ; AH := 0, AL := 1
  285.         out     dx,ax               ; Restore enable Set/Reset register
  286.  
  287.         pop        es
  288.         leave_c
  289.         ret
  290.  
  291. procend     __clear16
  292.  
  293. ;----------------------------------------------------------------------------
  294. ; void clear256(long color)
  295. ;----------------------------------------------------------------------------
  296. ; Routine to clear the screen. Assumes pages begin on bank boundaries
  297. ; for simplicity of coding.
  298. ;----------------------------------------------------------------------------
  299. procstart   __clear256
  300.  
  301.         ARG        color:ULONG
  302.  
  303.         enter_c 0
  304.         push    es
  305.  
  306.         xor        eax,eax
  307.         mov        al,[BYTE color]
  308.         mov        ebx,eax
  309.         shl        ebx,8
  310.         or        eax,ebx
  311.         mov        ebx,eax
  312.         shl        ebx,16
  313.         or        eax,ebx
  314.         mov        [color],eax            ; Color = 32 bit color value
  315.  
  316.         mov     _ax,[_maxy]
  317.         inc     _ax
  318.         mul     [_bytesperline]     ; DX:AX := number of bytes to fill
  319.         mov     bx,ax               ; BX := bytes in last bank to fill
  320.         mov     dh,dl               ; DH := number of full banks to fill
  321.  
  322.         mov        ax,fs
  323.         mov        es,ax
  324.         xor        _di,_di                ; ES:_DI -> start of video memory
  325.         add     di,[originOffset]
  326.         mov     dl,[BYTE bankOffset]; DL := starting bank number
  327.         cld                         ; Moves go up in memory
  328.  
  329.         or      dh,dh               ; More than one bank to fill?
  330.         jz      @@SingleBank        ; No, only fill a single bank
  331.  
  332. ; Fill all of the full 64k banks first
  333.  
  334. @@OuterLoop:
  335.         mov     al,dl
  336.         call    setBank
  337.         mov        eax,[color]
  338.         mov     _cx,4000h           ; Need to set 4000h double USHORTs per bank
  339.     rep stosd
  340.         xor        _di,_di
  341.         inc     dl
  342.         dec     dh
  343.         jnz     @@OuterLoop
  344.  
  345. ; Now fill the last partial bank
  346.  
  347. @@SingleBank:
  348.         mov     al,dl
  349.         call    setBank
  350.         mov        eax,[color]
  351.         xor     _cx,_cx
  352.         mov     cx,bx
  353.         shr     _cx,2               ; _CX := number of double USHORTs to set
  354.     rep stosd
  355.  
  356.         pop        es
  357.         leave_c
  358.         ret
  359.  
  360. procend     __clear256
  361.  
  362. ;----------------------------------------------------------------------------
  363. ; void clear32k(long color)
  364. ;----------------------------------------------------------------------------
  365. ; Routine to clear the screen. Assumes pages begin on bank boundaries
  366. ; for simplicity of coding.
  367. ;----------------------------------------------------------------------------
  368. procstart   __clear32k
  369.  
  370.         ARG        color:ULONG
  371.  
  372.         enter_c    0
  373.         push    es
  374.  
  375.         xor        eax,eax
  376.         mov        ax,[WORD color]
  377.         mov        ebx,eax
  378.         shl        ebx,16
  379.         or        eax,ebx
  380.         mov        [color],eax            ; Color = 32 bit color value
  381.  
  382.         mov     _ax,[_maxy]
  383.         inc     _ax
  384.         mul     [_bytesperline]     ; DX:AX := number of bytes to fill
  385.         mov     bx,ax               ; BX := bytes in last bank to fill
  386.         mov     dh,dl               ; DH := number of full banks to fill
  387.  
  388.         mov        ax,fs
  389.         mov        es,ax
  390.         xor        _di,_di                ; ES:_DI -> start of video memory
  391.         add     di,[originOffset]
  392.         mov     dl,[BYTE bankOffset]; DL := starting bank number
  393.         cld                         ; Moves go up in memory
  394.  
  395. ; Fill all of the full 64k banks first
  396.  
  397. @@OuterLoop:
  398.         mov     al,dl
  399.         call    setBank
  400.         mov        eax,[color]
  401.         mov     _cx,4000h           ; Need to set 4000h double USHORTs per bank
  402.     rep stosd
  403.         xor        _di,_di
  404.         inc     dl
  405.         dec     dh
  406.         jnz     @@OuterLoop
  407.  
  408. ; Now fill the last partial bank
  409.  
  410.         mov     al,dl
  411.         call    setBank
  412.         mov        eax,[color]
  413.         xor        _cx,_cx
  414.         mov     cx,bx
  415.         shr     _cx,2               ; _CX := number of double USHORTs to set
  416.     rep stosd
  417.  
  418.         pop        es
  419.         leave_c
  420.         ret
  421.  
  422. procend     __clear32k
  423.  
  424. ;----------------------------------------------------------------------------
  425. ; void clear16m(long color)
  426. ;----------------------------------------------------------------------------
  427. ; Routine to clear the screen. Assumes pages begin on bank boundaries
  428. ; for simplicity of coding.
  429. ;----------------------------------------------------------------------------
  430. procstart   __clear16m
  431.  
  432.         ARG        color:ULONG
  433.  
  434.         enter_c    0
  435.         push    _bp
  436.  
  437.         xor        _bx,_bx                ; FS:_BX -> start of video memory
  438.         add     bx,[originOffset]
  439.         mov     dl,[BYTE bankOffset]; DL := starting bank number
  440.         mov        ax,dx
  441.         call    setBank                ; Change to starting bank number
  442.  
  443.         mov        _di,[_maxx]
  444.         inc        _di                    ; _DI := number of pixels to draw
  445.         mov        _si,[_maxy]
  446.         inc        _si                    ; _SI := number of lines to process
  447.         mov        ax,[WORD color]        ; AX := pixel color
  448.         mov        dh,[BYTE color+2]    ; DH := top byte of pixel color
  449.         mov        bp,di
  450.         shl        bp,1
  451.         add        bp,di                ; BP := bytes per physical scanline
  452.         sub        bp,[_bytesperline]
  453.         neg        bp                    ; BP := scanline adjust factor
  454.  
  455. @@NextScanLine:
  456.         mov        _cx,_di
  457.  
  458. @@LoopSolid:
  459.         cmp        bx,0FFFDh
  460.         jae        @@BankSwitch        ; Bank switch occurs!
  461.  
  462.         mov        [WORD fs:_bx],ax    ; Set pixel value in buffer
  463.         mov        [BYTE fs:_bx+2],dh
  464.         add        _bx,3                ; Increment to next pixel
  465.         loop    @@LoopSolid            ; Loop across line
  466.  
  467. @@AfterPlot:
  468.         add        bx,bp
  469.         jc        @@BankSwitch2
  470.         dec        _si
  471.         jnz        @@NextScanLine
  472.         jmp        @@Exit
  473.  
  474. @@BankSwitch:
  475.         call    DrawPixelSlow16m
  476.         inc        dl
  477.         loop    @@LoopSolid            ; Loop across line
  478.         jmp        @@AfterPlot
  479.  
  480. @@BankSwitch2:
  481.         inc        dl
  482.         push    _ax
  483.         mov        _ax,_dx
  484.         call    setBank
  485.         pop        _ax
  486.         dec        _si
  487.         jnz        @@NextScanLine
  488.  
  489. @@Exit:
  490.         pop        _bp
  491.         leave_c
  492.         ret
  493.  
  494. procend     __clear16m
  495.  
  496. ;----------------------------------------------------------------------------
  497. ; void clear4G(long color)
  498. ;----------------------------------------------------------------------------
  499. ; Routine to clear the screen. Assumes pages begin on bank boundaries
  500. ; for simplicity of coding.
  501. ;----------------------------------------------------------------------------
  502. procstart   __clear4G
  503.  
  504.         ARG        color:ULONG
  505.  
  506.         enter_c    0
  507.         push    es
  508.  
  509.         mov     _ax,[_maxy]
  510.         inc     _ax
  511.         mul     [_bytesperline]     ; DX:AX := number of bytes to fill
  512.         mov     bx,ax               ; BX := bytes in last bank to fill
  513.         mov     dh,dl               ; DH := number of full banks to fill
  514.  
  515.         mov        ax,fs
  516.         mov        es,ax
  517.         xor        _di,_di                ; ES:_DI -> start of video memory
  518.         add     di,[originOffset]
  519.         mov     dl,[BYTE bankOffset]; DL := starting bank number
  520.         cld                         ; Moves go up in memory
  521.  
  522. ; Fill all of the full 64k banks first
  523.  
  524. @@OuterLoop:
  525.         mov     al,dl
  526.         call    setBank
  527.         mov     eax,[color]
  528.         mov     _cx,4000h           ; Need to set 4000h double USHORTs per bank
  529.     rep stosd
  530.         xor        _di,_di
  531.         inc     dl
  532.         dec     dh
  533.         jnz     @@OuterLoop
  534.  
  535. ; Now fill the last partial bank
  536.  
  537.         mov     al,dl
  538.         call    setBank
  539.         mov        eax,[color]
  540.         xor        _cx,_cx
  541.         mov     cx,bx
  542.         shr     _cx,2               ; _CX := number of double USHORTs to set
  543.     rep stosd
  544.  
  545.         pop        es
  546.         leave_c
  547.         ret
  548.  
  549. procend     __clear4G
  550.  
  551. ;----------------------------------------------------------------------------
  552. ; void putPixel16(int x,int y,long color)
  553. ;----------------------------------------------------------------------------
  554. ; Routine sets the value of a pixel in native VGA graphics modes.
  555. ;
  556. ; Entry:        x       -   X coordinate of pixel to draw
  557. ;               y       -   Y coordinate of pixel to draw
  558. ;               color   -   Color of pixel to draw
  559. ;
  560. ;----------------------------------------------------------------------------
  561. procstart   __putPixel16
  562.  
  563.         ARG     x:UINT, y:UINT, color:ULONG
  564.  
  565.         enter_c    0
  566.  
  567. ; Compute the pixel's address in video buffer
  568.  
  569.         mov     _ax,[y]
  570.         mov     _bx,[x]
  571.         mul     [_bytesperline]     ; DX:AX := y * BytesPerLine
  572.  
  573.         mov     cl,bl               ; CL := low-order byte of x
  574.  
  575.         shr     _bx,3               ; _BX := x/8
  576.         add     bx,ax
  577.         adc     dx,0                ; DX:BX := y*BytesPerLine + x/8
  578.         add     bx,[originOffset]   ; DX:BX := byte offset in video buffer
  579.         adc     dx,[bankOffset]
  580.  
  581.         cmp     dl,[BYTE _curBank]
  582.         je      @@NoChange
  583.  
  584.         mov     al,dl
  585.         call    setBank
  586.  
  587. @@NoChange:
  588.         mov     ah,1                ; AH := unshifted bit mask
  589.         and     cl,7                ; CL := x & 7
  590.         xor     cl,7                ; CL := # bits to shift left
  591.  
  592. ; set Graphics Controller Bit Mask register
  593.  
  594.         shl     ah,cl               ; AH := bit mask in proper postion
  595.         mov     dx,3CEh             ; GC address register port
  596.         mov     al,8                ; AL := Bit Mask Register number
  597.         out     dx,ax
  598.  
  599. ; set Graphics Controller Mode register
  600.  
  601.         mov     ax,0205h            ; AL := Mode register number
  602.                                     ; AH := Write mode 2 (bits 0,1)
  603.                                     ;   Read mode 0 (bit 3)
  604.         out     dx,ax
  605.  
  606. ; set data rotate/Function Select register
  607.  
  608.         mov     ax,3                ; AL := Data Rotate/Func select reg #
  609.         out     dx,ax
  610.  
  611. ; set the pixel value
  612.  
  613.         mov     al,[fs:_bx]           ; latch one byte from each bit plane
  614.         mov     al,[BYTE color]     ; AL := pixel value
  615.         mov     [fs:_bx],al           ; update all bit planes
  616.  
  617. ; restore default Graphics Controller registers
  618.  
  619.         mov     ax,0FF08h           ; default bit mask
  620.         out     dx,ax
  621.  
  622.         mov     ax,0005             ; default mode register
  623.         out     dx,ax
  624.  
  625.         mov     ax,0003             ; default function select
  626.         out     dx,ax
  627.  
  628.         leave_c
  629.         ret
  630.  
  631. procend     __putPixel16
  632.  
  633. ;----------------------------------------------------------------------------
  634. ; void putPixel256(int x,int y,long color)
  635. ;----------------------------------------------------------------------------
  636. ; Routine sets the value of a pixel in native VGA graphics modes.
  637. ;
  638. ; Entry:        x       -   X coordinate of pixel to draw
  639. ;               y       -   Y coordinate of pixel to draw
  640. ;               color   -   Color of pixel to draw
  641. ;
  642. ;----------------------------------------------------------------------------
  643. procstart   __putPixel256
  644.  
  645.         ARG     x:UINT, y:UINT, color:ULONG
  646.  
  647.         enter_c 0
  648.  
  649.         mov     _ax,[y]
  650.         mul     [_bytesperline]
  651.         mov     _bx,[x]
  652.         add     ax,bx
  653.         adc     dx,0                ; DX:AX := y * BytesPerLine + x
  654.         add     ax,[originOffset]
  655.         adc     dl,[BYTE bankOffset]; DL := bank number
  656.         mov     bx,ax               ; BX := Offset in buffer
  657.         cmp     dl,[BYTE _curBank]
  658.         je      @@NoChange
  659.  
  660.         mov     al,dl
  661.         call    setBank
  662.  
  663. @@NoChange:
  664.         mov     al,[BYTE color]
  665.         mov     [fs:_bx],al        ; Replace the pixel
  666.  
  667.         leave_c
  668.         ret
  669.  
  670. procend     __putPixel256
  671.  
  672. ;----------------------------------------------------------------------------
  673. ; void putPixel32k(int x,int y,long color)
  674. ;----------------------------------------------------------------------------
  675. ; Routine sets the value of a pixel in native VGA graphics modes.
  676. ;
  677. ; Entry:        x       -   X coordinate of pixel to draw
  678. ;               y       -   Y coordinate of pixel to draw
  679. ;               color   -   Color of pixel to draw
  680. ;
  681. ;----------------------------------------------------------------------------
  682. procstart   __putPixel32k
  683.  
  684.         ARG     x:UINT, y:UINT, color:ULONG
  685.  
  686.         enter_c    0
  687.  
  688.         mov     _ax,[y]
  689.         mul     [_bytesperline]
  690.         mov     _bx,[x]
  691.         shl     _bx,1
  692.         add     ax,bx
  693.         adc     dx,0                ; DX:AX := y * BytesPerLine + x * 2
  694.         add     ax,[originOffset]
  695.         adc     dl,[BYTE bankOffset]; DL := bank number
  696.         mov     bx,ax               ; BX := Offset in buffer
  697.         cmp     dl,[BYTE _curBank]
  698.         je      @@NoChange
  699.  
  700.         mov     al,dl
  701.         call    setBank
  702.  
  703. @@NoChange:
  704.         mov     ax,[USHORT color]
  705.         mov     [fs:_bx],ax            ; Replace the pixel
  706.  
  707.         leave_c
  708.         ret
  709.  
  710. procend     __putPixel32k
  711.  
  712. ;----------------------------------------------------------------------------
  713. ; void putPixel16m(int x,int y,long color)
  714. ;----------------------------------------------------------------------------
  715. ; Routine sets the value of a pixel in native VGA graphics modes.
  716. ;
  717. ; Entry:        x       -   X coordinate of pixel to draw
  718. ;               y       -   Y coordinate of pixel to draw
  719. ;               color   -   Color of pixel to draw
  720. ;
  721. ;----------------------------------------------------------------------------
  722. procstart   __putPixel16m
  723.  
  724.         ARG     x:UINT, y:UINT, color:ULONG
  725.  
  726.         enter_c    0
  727.  
  728.         mov     _ax,[y]
  729.         mul     [_bytesperline]
  730.         mov     _bx,[x]
  731.         add     ax,bx
  732.         adc     dx,0
  733.         shl     bx,1
  734.         add     ax,bx
  735.         adc     dx,0                ; DX:AX := y * BytesPerLine + x * 3
  736.         add     ax,[originOffset]
  737.         adc     dl,[BYTE bankOffset]; DL := bank number
  738.         mov     bx,ax               ; BX := Offset in buffer
  739.         cmp     dl,[BYTE _curBank]
  740.         je      @@NoChange
  741.  
  742.         mov     al,dl
  743.         call    setBank
  744.  
  745. @@NoChange:
  746.         mov     ax,[WORD color]
  747.         mov        dh,[BYTE color+2]
  748.         cmp        bx,0FFFEh
  749.         jae        @@SlowVersion        ; Bank switch occurs in pixel!
  750.  
  751.         mov     [fs:_bx],ax            ; Replace the first byte
  752.         mov        [fs:_bx+2],dh
  753.  
  754. @@Exit:    leave_c
  755.         ret
  756.  
  757. @@SlowVersion:
  758.         call    DrawPixelSlow16m    ; Draw the pixel slowly
  759.         jmp        @@Exit
  760.  
  761. procend     __putPixel16m
  762.  
  763. ;----------------------------------------------------------------------------
  764. ; IncBXDL    Increment the BX/DL offset bank number combination
  765. ;----------------------------------------------------------------------------
  766. ;
  767. ; This routine is called in place to increment the value of DL:BX where
  768. ; DL is the current bank offset, and BX is the current frame buffer offset.
  769. ; The routine also ensures that the bank boundary is correctly crossed. It
  770. ; is slow, but only gets called for about less than 10 pixels on the entire
  771. ; display page.
  772. ;
  773. ; Entry:        BX    - Video buffer offset
  774. ;                DL    - Video bank number
  775. ;
  776. ; Exit:            BX    - New buffer offset (+1)
  777. ;                DL    - New bank bumber (carried over from BX)
  778. ;
  779. ; Registers:    None.
  780. ;
  781. ;----------------------------------------------------------------------------
  782. PROC    IncBXDL    near
  783.  
  784.         add        bx,1
  785.         adc        dl,0
  786.         xchg    al,dl
  787.         call    setBank
  788.         xchg    al,dl
  789.         ret
  790.  
  791. ENDP    IncBXDL
  792.  
  793. ;----------------------------------------------------------------------------
  794. ; DrawPixelSlow16m    Draws a pixel split across a bank boundary correctly
  795. ;----------------------------------------------------------------------------
  796. ;
  797. ; Draws the pixel taking into account that a bank boundary occurs in the
  798. ; middle of the pixel.
  799. ;
  800. ; Entry:        DH:AX        - Color of the pixel to plot
  801. ;                FS:_BX        - Address of pixel to plot
  802. ;                _curBank    - Current bank number
  803. ;
  804. ; Exit:            DH:AX        - Color of pixel to plot
  805. ;                FS:_BX        - Address of pixel to plot + 3
  806. ;                _curBank    - Current bank number + 1
  807. ;
  808. ; Registers:    All preserved.
  809. ;
  810. ;----------------------------------------------------------------------------
  811. PROC    DrawPixelSlow16m    near
  812.  
  813.         push    _dx
  814.  
  815.         mov        dl,[BYTE _curBank]
  816.         mov        [fs:_bx],al            ; Replace the pixel
  817.         call    IncBXDL
  818.         mov        [fs:_bx],ah
  819.         call    IncBXDL
  820.         mov        [fs:_bx],dh
  821.         call    IncBXDL
  822.         pop        _dx
  823.         ret
  824.  
  825. ENDP    DrawPixelSlow16m
  826.  
  827. ;----------------------------------------------------------------------------
  828. ; void putPixel4G(int x,int y,long color)
  829. ;----------------------------------------------------------------------------
  830. ; Routine sets the value of a pixel in native VGA graphics modes.
  831. ;
  832. ; Entry:        x       -   X coordinate of pixel to draw
  833. ;               y       -   Y coordinate of pixel to draw
  834. ;               color   -   Color of pixel to draw
  835. ;
  836. ;----------------------------------------------------------------------------
  837. procstart   __putPixel4G
  838.  
  839.         ARG     x:UINT, y:UINT, color:ULONG
  840.  
  841.         enter_c    0
  842.  
  843.         mov     _ax,[y]
  844.         mul     [_bytesperline]
  845.         mov     _bx,[x]
  846.         shl     _bx,1
  847.         shl        _bx,1
  848.         add     ax,bx
  849.         adc     dx,0                ; DX:AX := y * BytesPerLine + x * 4
  850.         add     ax,[originOffset]
  851.         adc     dl,[BYTE bankOffset]; DL := bank number
  852.         mov     bx,ax               ; BX := Offset in buffer
  853.         cmp     dl,[BYTE _curBank]
  854.         je      @@NoChange
  855.  
  856.         mov     al,dl
  857.         call    setBank
  858.  
  859. @@NoChange:
  860.         mov     eax,[color]
  861.         mov     [fs:_BX],eax           ; Replace the pixel
  862.  
  863.         leave_c
  864.         ret
  865.  
  866. procend     __putPixel4G
  867.  
  868. ;----------------------------------------------------------------------------
  869. ; void _line16(int x1,int y1,int x2,int y2, long color)
  870. ;----------------------------------------------------------------------------
  871. ; Routine draws a line in native VGA graphics modes.
  872. ;
  873. ; Differentiates between horizontal, vertical and sloping lines. Horizontal
  874. ; and vertical lines are special cases and can be drawn extremely quickly.
  875. ; The sloping lines are drawn using the Midpoint line algorithm.
  876. ;
  877. ; Entry:        x1        - X1 coordinate of line to draw
  878. ;                y1        - Y1 coordinate of line to draw
  879. ;                x2        - X2 coordinate of line to draw
  880. ;                y2        - Y2 coordinate of line to draw
  881. ;                color    - color to draw the line in
  882. ;
  883. ;----------------------------------------------------------------------------
  884. procstart    __line16
  885.  
  886.         ARG        x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
  887.         LOCAL    Routine:NCPTR, VertInc:ULONG, EIncr:UINT,             \
  888.                 NEIncr:UINT = LocalSize
  889.  
  890.         enter_c    LocalSize
  891.         cld
  892.  
  893. ; Configure the graphics controller (write mode 3)
  894.  
  895.         mov        dx,3CEh                ; DX := Graphics Controller port addr
  896.  
  897.         mov        ax,0B05h            ; AL := Mode register number
  898.                                     ; AH := Write mode 3 (bits 0,1)
  899.                                     ;    Read mode 1 (bit 3)
  900.         out        dx,ax
  901.  
  902.         xor        ah,ah                ; AH := replace mode
  903.         mov        al,3                ; AL := Data Rotate/Func select reg #
  904.         out        dx,ax
  905.  
  906.         mov        ax,0007h            ; AH := 0 (don't care for all maps;
  907.                                     ;    CPU reads always return 0FFH)
  908.                                     ; AL := 7 (Color Don't care reg number)
  909.         out        dx,ax                ; Set up Color Don't care reg
  910.  
  911.         mov        ax,0F01h            ; AH := 1111b (bit plane mask for
  912.                                     ;  enable Set/Reset)
  913.         out        dx,ax                ; AL := Enable Set/Reset Register #
  914.  
  915.         mov        ax,0FF08h            ; AH := 11111111b, AL := 8
  916.         out        dx,ax                ; restore bit mask register
  917.  
  918. ; Load the current color
  919.  
  920.         mov        dx,3CEh                ; DX := Graphics Controller port addr
  921.         mov        ah,[BYTE color]        ; Get color value into ah
  922.         xor        al,al                ; AL := Set/Reset Register number
  923.         out        dx,ax
  924.  
  925.         mov        si,[_bytesperline]    ; Increment for video buffer
  926.         mov        [USHORT VertInc+2],0    ; Zero out sign for vertical increment
  927.         mov        _ax,[x2]
  928.         sub        _ax,[x1]            ; _AX := X2 - X1
  929.  
  930. ; Force X1 < X2
  931.  
  932.         jns        @@X2Greater            ; Jump if X2 > X1
  933.         neg        _ax                    ; _AX := X1 - X2
  934.  
  935.         mov        _bx,[x2]            ; Exchange X1 and X2
  936.         xchg    _bx,[x1]
  937.         mov        [x2],_bx
  938.  
  939.         mov        _bx,[y2]            ; Exchange Y1 and Y2
  940.         xchg    _bx,[y1]
  941.         mov        [y2],_bx
  942.  
  943. ; calcluate dy = ABS(Y2-Y1)
  944.  
  945. @@X2Greater:
  946.         mov        _bx,[y2]
  947.         sub        _bx,[y1]            ; _BX := Y2 - Y1
  948.         jns        @@Y2Greater            ; Jump if slope is positive
  949.  
  950.         neg        _bx                    ; _BX := Y1 - Y2
  951.         neg        si                    ; negative increment for buffer
  952.         mov        [USHORT VertInc+2],0FFFFh    ; ensure vert increment is negative
  953.  
  954. ; select appropriate routine for slope of line
  955.  
  956. @@Y2Greater:
  957.         mov        [USHORT VertInc],si    ; save increment
  958.         mov        [Routine],offset @@LoSlopeLine
  959.         cmp        _bx,_ax
  960.         jle        @@LoSlope            ; Jump if dy <= dx (Slope <= 1)
  961.         mov        [Routine],offset @@HiSlopeLine
  962.         xchg    _bx,_ax                ; exchange dy and dx
  963.  
  964. ; calculate initial decision variable and increments
  965.  
  966. @@LoSlope:
  967.         shl        _bx,1                ; _BX := 2 * dy
  968.         mov        [EIncr],_bx            ; EIncr := 2 * dy
  969.         sub        _bx,_ax                ; d = 2 * dy - dx
  970.         mov        _di,_bx                ; DI := initial decision variable
  971.         sub        _bx,_ax
  972.         mov        [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)
  973.  
  974. ; calculate first pixel address
  975.  
  976.         push    _ax                    ; preserve dx
  977.         mov        _ax,[y1]
  978.         mov        _bx,[x1]
  979.         call    PixelAddr16            ; AH := Bit mask
  980.                                     ; FS:_BX -> buffer
  981.                                     ; CL := # bits to shift left
  982.                                     ; _SI := bank number
  983.         shl        ah,cl                ; AH := bit mask in proper position
  984.         mov        al,ah                ; AL := bit Mask
  985.         pop        _cx                    ; Restore dx
  986.         inc        _cx                    ; _CX := # pixels to draw
  987.  
  988.         jmp        [Routine]            ; jump to appropriate routine
  989.  
  990. ;****************************************************************************
  991. ;
  992. ; Routine for dy <= dx (slope <= 1)
  993. ;                        FS:_BX -> video buffer
  994. ;                        AL = bit mask for 1st pixel
  995. ;                        AH = bit mask for 1st pixel
  996. ;                        _CX = # pixels to draw
  997. ;                        DX = Graphics Controller data register port addr
  998. ;                        _SI = bank number
  999. ;                        _DI = Initial decision variable
  1000. ;                        EIncr    - East pixel increment
  1001. ;                        NEIncr    - North East pixel increment
  1002. ;
  1003. ; The Graphics Controller index register should be set to point to the
  1004. ; Bit Mask register.
  1005. ;
  1006. ;****************************************************************************
  1007.  
  1008. @@LoSlopeLine:
  1009.  
  1010. @@StartLo:
  1011.         mov        al,ah                ; AL := bit mask for next pixel
  1012.         cmp        si,[USHORT _curBank]
  1013.         je        @@BitMaskIn
  1014.  
  1015.         push    _ax                    ; Preserve AX
  1016.         mov        _ax,_si                ; AX := new bank number
  1017.         call    setBank                ; Program this bank
  1018.         pop        _ax
  1019.  
  1020. @@BitMaskIn:
  1021.         or        al,ah                ; mask current pixel position
  1022.         ror        ah,1                ; Rotate pixel value
  1023.         jc        @@BitMaskOut        ; Jump if mask rotated to leftmost pixel
  1024.  
  1025. ; bit mask not shifted out
  1026.  
  1027.         or        _di,_di                ; test sign of d
  1028.         jns        @@InPosDi            ; jump if d >= 0
  1029.  
  1030.         add        _di,[EIncr]            ; d := d + EIncr
  1031.         loop    @@BitMaskIn
  1032.  
  1033.         and        [fs:_bx],al            ; set remaining pixel(s)
  1034.         jmp        @@Exit
  1035.  
  1036. @@InPosDi:
  1037.         add        _di,[NEIncr]        ; d := d + NEIncr
  1038.  
  1039.         and        [fs:_bx],al            ; Update bit planes
  1040.  
  1041.         add        bx,[USHORT VertInc]    ; increment y
  1042.         adc        si,[USHORT VertInc+2]    ; Adjust bank number
  1043.         loop    @@StartLo
  1044.         jmp        @@Exit
  1045.  
  1046. ; bit mask shifted out
  1047.  
  1048. @@BitMaskOut:
  1049.         and        [fs:_bx],al            ; Update bit planes
  1050.         add        bx,1                ; increment x
  1051.         adc        si,0                ; Adjust bank value
  1052.  
  1053.         or        _di,_di                ; test sign of d
  1054.         jns        @@OutPosDi            ; jump if non-negative
  1055.  
  1056.         add        _di,[EIncr]            ; d := d + EIncr
  1057.         loop    @@StartLo
  1058.         jmp        @@Exit
  1059.  
  1060. @@OutPosDi:
  1061.         add        _di,[NEIncr]        ; d := d + NEIncr
  1062.         add        bx,[USHORT VertInc]    ; vertical increment
  1063.         adc        si,[USHORT VertInc+2]    ; Adjust bank number
  1064.         loop    @@StartLo
  1065.         jmp        @@Exit
  1066.  
  1067. ;****************************************************************************
  1068. ;
  1069. ; Routine for dy > dx (slope > 1)
  1070. ;                        FS:_BX -> video buffer
  1071. ;                        AL = bit mask for 1st pixel
  1072. ;                        _CX = # pixels to draw
  1073. ;                        DX = Graphics Controller data register port addr
  1074. ;                        _SI = bank number
  1075. ;                        _DI = Initial decision variable
  1076. ;                        EIncr    - East pixel increment
  1077. ;                        NEIncr    - North East pixel increment
  1078. ;
  1079. ; The Graphics Controller index register should be set to point to the
  1080. ; Bit Mask register.
  1081. ;
  1082. ;****************************************************************************
  1083.  
  1084. @@HiSlopeLine:
  1085.  
  1086. @@StartHi:
  1087.         cmp        si,[USHORT _curBank]
  1088.         je        @@SetHi
  1089.  
  1090.         push    _ax                    ; Preserve AX
  1091.         mov        _ax,_si                ; AX := new bank number
  1092.         call    setBank                ; Program this bank
  1093.         pop        _ax
  1094.  
  1095. @@SetHi:
  1096.         and        [fs:_bx],al            ; update bit planes
  1097.  
  1098.         add        bx,[USHORT VertInc]    ; increment y
  1099.         adc        si,[USHORT VertInc+2]    ; Adjust bank number
  1100.  
  1101.         or        _di,_di                ; test sign of d
  1102.         jns        @@HiPosDi            ; jump if d >= 0
  1103.  
  1104.         add        _di,[EIncr]            ; d := d + EIncr
  1105.         loop    @@StartHi
  1106.         jmp        @@Exit
  1107.  
  1108. @@HiPosDi:
  1109.         add        _di,[NEIncr]        ; d := d + NEIncr
  1110.  
  1111.         ror        al,1                ; rotate bit mask
  1112.         adc        bx,0                ; Increment BX when mask rotated to
  1113.                                     ;  leftmost pixel position
  1114.         adc        si,0                ; Adjust bank number
  1115.         loop    @@StartHi
  1116.  
  1117. ; Restore graphics controller and return to caller
  1118.  
  1119. @@Exit:
  1120.         mov        dx,3CEh                ; DX := Graphics Controller port addr
  1121.         xor        ax,ax                ; AH := 0, AL := 0
  1122.         out        dx,ax                ; Restore Set/Reset Register
  1123.  
  1124.         inc        ax                    ; AH := 0, AL := 1
  1125.         out        dx,ax                ; Restore Enable Set/Reset register
  1126.  
  1127.         mov        al,3                ; AH := 0, AL := 3
  1128.         out        dx,ax                ; Restore Data Rotate/Func select reg
  1129.  
  1130.         mov        al,5                ; AH := 0, AL := 5
  1131.         out        dx,ax                ; default mode register
  1132.  
  1133.         mov        ax,0F07h            ; default color compare value
  1134.         out        dx,ax
  1135.  
  1136.         mov        ax,0FF08h            ; AH := 11111111b, AL := 8
  1137.         out        dx,ax                ; restore bit mask register
  1138.  
  1139.         leave_c
  1140.         ret
  1141.  
  1142. procend        __line16
  1143.  
  1144. ;----------------------------------------------------------------------------
  1145. ; void _line256(int x1,int y1,int x2,int y2, long color)
  1146. ;----------------------------------------------------------------------------
  1147. ; Routine draws a line in native VGA graphics modes.
  1148. ;
  1149. ; Differentiates between horizontal, vertical and sloping lines. Horizontal
  1150. ; and vertical lines are special cases and can be drawn extremely quickly.
  1151. ; The sloping lines are drawn using the Midpoint line algorithm.
  1152. ;
  1153. ; Entry:        x1        - X1 coordinate of line to draw
  1154. ;                y1        - Y1 coordinate of line to draw
  1155. ;                x2        - X2 coordinate of line to draw
  1156. ;                y2        - Y2 coordinate of line to draw
  1157. ;                color    - color to draw the line in
  1158. ;
  1159. ;----------------------------------------------------------------------------
  1160. procstart    __line256
  1161.  
  1162.         ARG        x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
  1163.         LOCAL    Routine:NCPTR, VertInc:ULONG, EIncr:UINT,             \
  1164.                 NEIncr:UINT = LocalSize
  1165.  
  1166.         enter_c    LocalSize
  1167.  
  1168.         mov        si,[_bytesperline]    ; Increment for video buffer
  1169.         mov        [USHORT VertInc+2],0    ; Zero out sign for vertical increment
  1170.  
  1171.         mov        _ax,[x2]
  1172.         sub        _ax,[x1]            ; _AX := X2 - X1
  1173.  
  1174. ; Force X1 < X2
  1175.  
  1176.         jns        @@X2Greater            ; Jump if X2 > X1
  1177.         neg        _ax                    ; _AX := X1 - X2
  1178.  
  1179.         mov        _bx,[x2]            ; Exchange X1 and X2
  1180.         xchg    _bx,[x1]
  1181.         mov        [x2],_bx
  1182.  
  1183.         mov        _bx,[y2]            ; Exchange Y1 and Y2
  1184.         xchg    _bx,[y1]
  1185.         mov        [y2],_bx
  1186.  
  1187. ; calcluate dy = ABS(Y2-Y1)
  1188.  
  1189. @@X2Greater:
  1190.         mov        _bx,[y2]
  1191.         sub        _bx,[y1]            ; _BX := Y2 - Y1
  1192.         jns        @@Y2Greater            ; Jump if slope is positive
  1193.  
  1194.         neg        _bx                    ; _BX := Y1 - Y2
  1195.         neg        si                    ; negative increment for buffer
  1196.         mov        [USHORT VertInc+2],0FFFFh    ; ensure vert increment is negative
  1197.  
  1198. ; select appropriate routine for slope of line
  1199.  
  1200. @@Y2Greater:
  1201.         mov        [USHORT VertInc],si    ; save increment
  1202.         mov        [Routine],offset @@LoSlopeLine
  1203.         cmp        _bx,_ax
  1204.         jle        @@LoSlope            ; Jump if dy <= dx (Slope <= 1)
  1205.         mov        [Routine],offset @@HiSlopeLine
  1206.         xchg    _bx,_ax                ; exchange dy and dx
  1207.  
  1208. ; calculate initial decision variable and increments
  1209.  
  1210. @@LoSlope:
  1211.         shl        _bx,1                ; _BX := 2 * dy
  1212.         mov        [EIncr],_bx            ; EIncr := 2 * dy
  1213.         sub        _bx,_ax                ; d = 2 * dy - dx
  1214.         mov        _di,_bx                ; _DI := initial decision variable
  1215.         sub        _bx,_ax
  1216.         mov        [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)
  1217.  
  1218. ; calculate first pixel address
  1219.  
  1220.         push    _ax                    ; preserve dx
  1221.         mov        _ax,[y1]
  1222.         mov        _bx,[x1]
  1223.         call    PixelAddr256        ; FS:_BX -> buffer
  1224.  
  1225.         pop        _cx                    ; Restore dx
  1226.         inc        _cx                    ; CX := # pixels to draw
  1227.  
  1228.         jmp     [Routine]           ; jump to appropriate routine
  1229.  
  1230. ;****************************************************************************
  1231. ;
  1232. ; Routine for dy <= dx (slope <= 1)
  1233. ;                        FS:_BX -> video buffer
  1234. ;                        _CX = # pixels to draw
  1235. ;                        _DX = Bank number for first pixel
  1236. ;                        _DI = decision variable
  1237. ;                        EIncr    - East pixel increment
  1238. ;                        NEIncr    - North East pixel increment
  1239. ;
  1240. ;****************************************************************************
  1241.  
  1242. @@LoSlopeLine:
  1243.         mov        al,0
  1244.         call    setBank
  1245.         mov        al,[BYTE color]        ; AL := pixel value to fill
  1246.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1247.  
  1248. @@LoopLo:
  1249.         cmp        dl,dh
  1250.         je        @@SetLo
  1251.  
  1252.         mov        dh,al                ; DH := color value
  1253.         mov        al,dl                ; AL := new bank number
  1254.         call    setBank                ; Program this bank
  1255.         mov        al,dh                ; AL := color value
  1256.         mov        dh,dl                ; DH := current bank number
  1257.  
  1258. @@SetLo:
  1259.         mov        [fs:_bx],al            ; Set pixel value in buffer
  1260.         add        bx,1                ; Increment x coordinate
  1261.         adc        dl,0                ; Adjust bank number
  1262.         or        _di,_di                ; Test sign of d
  1263.         jns        @@LoPosDi            ; Jump if d >= 0
  1264.  
  1265.         add        _di,[EIncr]            ; d := d + EIncr
  1266.         loop    @@LoopLo            ; Loop for remaining pixels
  1267.         jmp        @@Exit                ; We are all done
  1268.  
  1269. @@LoPosDi:
  1270.         add        _di,[NEIncr]        ; d := d + NEIncr
  1271.         add        bx,[USHORT VertInc]    ; increment y
  1272.         adc        dl,[BYTE VertInc+2]    ; adjust page number
  1273.         loop    @@LoopLo            ; Loop for remaining pixels
  1274.         jmp        @@Exit                ; We are all done
  1275.  
  1276. ;****************************************************************************
  1277. ;
  1278. ; Routine for dy > dx (slope > 1)
  1279. ;                        ES:_BX -> video buffer
  1280. ;                        _CX = # pixels to draw
  1281. ;                        _DX = Bank number for first pixel
  1282. ;                        _DI = decision variable
  1283. ;                        EIncr    - East pixel increment
  1284. ;                        NEIncr    - North East pixel increment
  1285. ;
  1286. ;****************************************************************************
  1287.  
  1288. @@HiSlopeLine:
  1289.         mov        al,[BYTE color]        ; AL := pixel value to fill
  1290.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1291.  
  1292. @@LoopHi:
  1293.         cmp        dh,dl
  1294.         je        @@SetHi
  1295.  
  1296.         mov        dh,al                ; DH := color value
  1297.         mov        al,dl                ; AL := new bank number
  1298.         call    setBank                ; Program this bank
  1299.         mov        al,dh                ; AL := color value
  1300.         mov        dh,dl                ; DH := current bank number
  1301.  
  1302. @@SetHi:
  1303.         mov        [fs:_bx],al            ; Set pixel value in buffer
  1304.         add        bx,[USHORT VertInc]    ; increment y
  1305.         adc        dl,[BYTE VertInc+2]    ; Adjust bank number
  1306.         or        _di,_di                ; Test sign of d
  1307.         jns        @@HiPosDi            ; Jump if d >= 0
  1308.  
  1309.         add        _di,[EIncr]            ; d := d + EIncr
  1310.         loop    @@LoopHi            ; Loop for remaining pixels
  1311.         jmp        @@Exit                ; We are all done
  1312.  
  1313. @@HiPosDi:
  1314.         add        _di,[NEIncr]        ; d := d + NEIncr
  1315.         add        bx,1                ; Increment x
  1316.         adc        dl,0                ; Adjust bank number
  1317.         loop    @@LoopHi            ; Loop for remaining pixels
  1318.  
  1319. @@Exit:
  1320.         leave_c
  1321.         ret
  1322.  
  1323. procend        __line256
  1324.  
  1325. ;----------------------------------------------------------------------------
  1326. ; void _line32k(int x1,int y1,int x2,int y2, long color)
  1327. ;----------------------------------------------------------------------------
  1328. ; Routine draws a line in native VGA graphics modes.
  1329. ;
  1330. ; Differentiates between horizontal, vertical and sloping lines. Horizontal
  1331. ; and vertical lines are special cases and can be drawn extremely quickly.
  1332. ; The sloping lines are drawn using the Midpoint line algorithm.
  1333. ;
  1334. ; Entry:        x1        - X1 coordinate of line to draw
  1335. ;                y1        - Y1 coordinate of line to draw
  1336. ;                x2        - X2 coordinate of line to draw
  1337. ;                y2        - Y2 coordinate of line to draw
  1338. ;                color    - color to draw the line in
  1339. ;
  1340. ;----------------------------------------------------------------------------
  1341. procstart    __line32k
  1342.  
  1343.         ARG        x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
  1344.         LOCAL    Routine:NCPTR, VertInc:ULONG, EIncr:UINT,             \
  1345.                 NEIncr:UINT = LocalSize
  1346.  
  1347.         enter_c    LocalSize
  1348.         cld
  1349.  
  1350.         mov        si,[_bytesperline]    ; Increment for video buffer
  1351.         mov        [USHORT VertInc+2],0    ; Zero out sign for vertical increment
  1352.  
  1353.         mov        _ax,[x2]
  1354.         sub        _ax,[x1]            ; _AX := X2 - X1
  1355.  
  1356. ; Force X1 < X2
  1357.  
  1358.         jns        @@X2Greater            ; Jump if X2 > X1
  1359.         neg        _ax                    ; _AX := X1 - X2
  1360.  
  1361.         mov        _bx,[x2]            ; Exchange X1 and X2
  1362.         xchg    _bx,[x1]
  1363.         mov        [x2],_bx
  1364.  
  1365.         mov        _bx,[y2]            ; Exchange Y1 and Y2
  1366.         xchg    _bx,[y1]
  1367.         mov        [y2],_bx
  1368.  
  1369. ; calcluate dy = ABS(Y2-Y1)
  1370.  
  1371. @@X2Greater:
  1372.         mov        _bx,[y2]
  1373.         sub        _bx,[y1]            ; _BX := Y2 - Y1
  1374.         jns        @@Y2Greater            ; Jump if slope is positive
  1375.  
  1376.         neg        _bx                    ; _BX := Y1 - Y2
  1377.         neg        si                    ; negative increment for buffer
  1378.         mov        [USHORT VertInc+2],0FFFFh    ; ensure vert increment is negative
  1379.  
  1380. ; select appropriate routine for slope of line
  1381.  
  1382. @@Y2Greater:
  1383.         mov        [USHORT VertInc],si    ; save increment
  1384.         mov        [Routine],offset @@LoSlopeLine
  1385.         cmp        _bx,_ax
  1386.         jle        @@LoSlope            ; Jump if dy <= dx (Slope <= 1)
  1387.         mov        [Routine],offset @@HiSlopeLine
  1388.         xchg    _bx,_ax                ; exchange dy and dx
  1389.  
  1390. ; calculate initial decision variable and increments
  1391.  
  1392. @@LoSlope:
  1393.         shl        _bx,1                ; _BX := 2 * dy
  1394.         mov        [EIncr],_bx            ; EIncr := 2 * dy
  1395.         sub        _bx,_ax                ; d = 2 * dy - dx
  1396.         mov        _di,_bx                ; _DI := initial decision variable
  1397.         sub        _bx,_ax
  1398.         mov        [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)
  1399.  
  1400. ; calculate first pixel address
  1401.  
  1402.         push    _ax                    ; preserve dx
  1403.         mov        _ax,[y1]
  1404.         mov        _bx,[x1]
  1405.         call    PixelAddr32k        ; FS:_BX -> buffer
  1406.  
  1407.         pop        _cx                    ; Restore dx
  1408.         inc        _cx                    ; _CX := # pixels to draw
  1409.  
  1410.         jmp        [Routine]            ; jump to appropriate routine
  1411.  
  1412. ;****************************************************************************
  1413. ;
  1414. ; Routine for dy <= dx (slope <= 1)
  1415. ;                        FS:_BX -> video buffer
  1416. ;                        _CX = # pixels to draw
  1417. ;                        _DX = Bank number for first pixel
  1418. ;                        _DI = decision variable
  1419. ;                        EIncr    - East pixel increment
  1420. ;                        NEIncr    - North East pixel increment
  1421. ;
  1422. ;****************************************************************************
  1423.  
  1424. @@LoSlopeLine:
  1425.         mov        ax,[USHORT color]        ; AX := pixel value to fill
  1426.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1427.  
  1428. @@LoopLo:
  1429.         cmp        dl,dh
  1430.         je        @@SetLo
  1431.  
  1432.         push    _ax                    ; Save color value
  1433.         mov        al,dl                ; AL := new bank number
  1434.         call    setBank                ; Program this bank
  1435.         mov        dh,dl                ; DH := current bank number
  1436.         pop        _ax                    ; Restore color value
  1437.  
  1438. @@SetLo:
  1439.         mov        [fs:_bx],ax            ; Set pixel value in buffer
  1440.         add        bx,2                ; Increment x coordinate
  1441.         adc        dl,0                ; Adjust bank number
  1442.         or        _di,_di                ; Test sign of d
  1443.         jns        @@LoPosDi            ; Jump if d >= 0
  1444.  
  1445.         add        _di,[EIncr]            ; d := d + EIncr
  1446.         loop    @@LoopLo            ; Loop for remaining pixels
  1447.         jmp        @@Exit                ; We are all done
  1448.  
  1449. @@LoPosDi:
  1450.         add        _di,[NEIncr]        ; d := d + NEIncr
  1451.         add        bx,[USHORT VertInc]    ; increment y
  1452.         adc        dl,[BYTE VertInc+2]    ; adjust page number
  1453.         loop    @@LoopLo            ; Loop for remaining pixels
  1454.         jmp        @@Exit                ; We are all done
  1455.  
  1456. ;****************************************************************************
  1457. ;
  1458. ; Routine for dy > dx (slope > 1)
  1459. ;                        FS:_BX -> video buffer
  1460. ;                        _CX = # pixels to draw
  1461. ;                        _DX = Bank number for first pixel
  1462. ;                        _DI = decision variable
  1463. ;                        EIncr    - East pixel increment
  1464. ;                        NEIncr    - North East pixel increment
  1465. ;
  1466. ;****************************************************************************
  1467.  
  1468. @@HiSlopeLine:
  1469.         mov        ax,[USHORT color]        ; AL := pixel value to fill
  1470.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1471.  
  1472. @@LoopHi:
  1473.         cmp        dh,dl
  1474.         je        @@SetHi
  1475.  
  1476.         push    _ax                    ; Save color value
  1477.         mov        al,dl                ; AL := new bank number
  1478.         call    setBank                ; Program this bank
  1479.         mov        dh,dl                ; DH := current bank number
  1480.         pop        _ax                    ; Restore color value
  1481.  
  1482. @@SetHi:
  1483.         mov        [fs:_bx],ax            ; Set pixel value in buffer
  1484.         add        bx,[USHORT VertInc]    ; increment y
  1485.         adc        dl,[BYTE VertInc+2]    ; Adjust bank number
  1486.         or        _di,_di                ; Test sign of d
  1487.         jns        @@HiPosDi            ; Jump if d >= 0
  1488.  
  1489.         add        _di,[EIncr]            ; d := d + EIncr
  1490.         loop    @@LoopHi            ; Loop for remaining pixels
  1491.         jmp        @@Exit                ; We are all done
  1492.  
  1493. @@HiPosDi:
  1494.         add        _di,[NEIncr]        ; d := d + NEIncr
  1495.         add        bx,2                ; Increment x
  1496.         adc        dl,0                ; Adjust bank number
  1497.         loop    @@LoopHi            ; Loop for remaining pixels
  1498.  
  1499. @@Exit:
  1500.         leave_c
  1501.         ret
  1502.  
  1503. procend        __line32k
  1504.  
  1505. ;----------------------------------------------------------------------------
  1506. ; void _line16m(int x1,int y1,int x2,int y2, long color)
  1507. ;----------------------------------------------------------------------------
  1508. ; Routine draws a line in native VGA graphics modes.
  1509. ;
  1510. ; Differentiates between horizontal, vertical and sloping lines. Horizontal
  1511. ; and vertical lines are special cases and can be drawn extremely quickly.
  1512. ; The sloping lines are drawn using the Midpoint line algorithm.
  1513. ;
  1514. ; Entry:        x1        - X1 coordinate of line to draw
  1515. ;                y1        - Y1 coordinate of line to draw
  1516. ;                x2        - X2 coordinate of line to draw
  1517. ;                y2        - Y2 coordinate of line to draw
  1518. ;                color    - color to draw the line in
  1519. ;
  1520. ;----------------------------------------------------------------------------
  1521. procstart    __line16m
  1522.  
  1523.         ARG        x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
  1524.         LOCAL    Routine:NCPTR, VertInc:ULONG, EIncr:UINT,             \
  1525.                 NEIncr:UINT = LocalSize
  1526.  
  1527.         enter_c    LocalSize
  1528.         cld
  1529.  
  1530.         mov        si,[_bytesperline]    ; Increment for video buffer
  1531.         mov        [USHORT VertInc+2],0    ; Zero out sign for vertical increment
  1532.  
  1533.         mov        _ax,[x2]
  1534.         sub        _ax,[x1]            ; _AX := X2 - X1
  1535.  
  1536. ; Force X1 < X2
  1537.  
  1538.         jns        @@X2Greater            ; Jump if X2 > X1
  1539.         neg        _ax                    ; _AX := X1 - X2
  1540.  
  1541.         mov        _bx,[x2]            ; Exchange X1 and X2
  1542.         xchg    _bx,[x1]
  1543.         mov        [x2],_bx
  1544.  
  1545.         mov        _bx,[y2]            ; Exchange Y1 and Y2
  1546.         xchg    _bx,[y1]
  1547.         mov        [y2],_bx
  1548.  
  1549. ; calcluate dy = ABS(Y2-Y1)
  1550.  
  1551. @@X2Greater:
  1552.         mov        _bx,[y2]
  1553.         sub        _bx,[y1]            ; _BX := Y2 - Y1
  1554.         jns        @@Y2Greater            ; Jump if slope is positive
  1555.  
  1556.         neg        _bx                    ; _BX := Y1 - Y2
  1557.         neg        si                    ; negative increment for buffer
  1558.         mov        [USHORT VertInc+2],0FFFFh    ; ensure vert increment is negative
  1559.  
  1560. ; select appropriate routine for slope of line
  1561.  
  1562. @@Y2Greater:
  1563.         mov        [USHORT VertInc],si    ; save increment
  1564.         mov        [Routine],offset @@LoSlopeLine
  1565.         cmp        _bx,_ax
  1566.         jle        @@LoSlope            ; Jump if dy <= dx (Slope <= 1)
  1567.         mov        [Routine],offset @@HiSlopeLine
  1568.         xchg    _bx,_ax                ; exchange dy and dx
  1569.  
  1570. ; calculate initial decision variable and increments
  1571.  
  1572. @@LoSlope:
  1573.         shl        _bx,1                ; _BX := 2 * dy
  1574.         mov        [EIncr],_bx            ; EIncr := 2 * dy
  1575.         sub        _bx,_ax                ; d = 2 * dy - dx
  1576.         mov        _di,_bx                ; _DI := initial decision variable
  1577.         sub        _bx,_ax
  1578.         mov        [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)
  1579.  
  1580. ; calculate first pixel address
  1581.  
  1582.         push    _ax                    ; preserve dx
  1583.         mov        _ax,[y1]
  1584.         mov        _bx,[x1]
  1585.         call    PixelAddr16m        ; FS:_BX -> buffer
  1586.  
  1587.         pop        _cx                    ; Restore dx
  1588.         inc        _cx                    ; CX := # pixels to draw
  1589.  
  1590.         jmp        [Routine]            ; jump to appropriate routine
  1591.  
  1592. ;****************************************************************************
  1593. ;
  1594. ; Routine for dy <= dx (slope <= 1)
  1595. ;                        FS:_BX -> video buffer
  1596. ;                        _CX = # pixels to draw
  1597. ;                        _DX = Bank number for first pixel
  1598. ;                        _DI = decision variable
  1599. ;                        EIncr    - East pixel increment
  1600. ;                        NEIncr    - North East pixel increment
  1601. ;
  1602. ;****************************************************************************
  1603.  
  1604. @@LoSlopeLine:
  1605.         mov        ax,[USHORT color]        ; AX := pixel value to fill
  1606.         mov        dh,[BYTE color+2]    ; DH := top byte of pixel value
  1607.  
  1608. @@LoopLo:
  1609.         cmp        dl,[BYTE _curBank]
  1610.         je        @@SetPixelLo
  1611.  
  1612.         push    _ax                    ; Save color value
  1613.         mov        al,dl                ; AL := new bank number
  1614.         call    setBank                ; Program this bank
  1615.         pop        _ax                    ; Restore color value
  1616.  
  1617. @@SetPixelLo:
  1618.         cmp        bx,0FFFEh
  1619.         jae        @@BankSwitchLo
  1620.  
  1621. @@SetLo:
  1622.         mov        [fs:_bx],ax            ; Set pixel value in buffer
  1623.         mov        [fs:_bx+2],dh
  1624.         add        bx,3                ; Increment x coordinate
  1625.         adc        dl,0                ; Adjust bank number
  1626.  
  1627. @@DonePixelLo:
  1628.         or        _di,_di                ; Test sign of d
  1629.         jns        @@LoPosDi            ; Jump if d >= 0
  1630.  
  1631.         add        _di,[EIncr]            ; d := d + EIncr
  1632.         loop    @@LoopLo            ; Loop for remaining pixels
  1633.         jmp        @@Exit                ; We are all done
  1634.  
  1635. @@LoPosDi:
  1636.         add        _di,[NEIncr]        ; d := d + NEIncr
  1637.         add        bx,[USHORT VertInc]    ; increment y
  1638.         adc        dl,[BYTE VertInc+2]    ; adjust page number
  1639.         loop    @@LoopLo            ; Loop for remaining pixels
  1640.         jmp        @@Exit                ; We are all done
  1641.  
  1642. @@BankSwitchLo:
  1643.         call    DrawPixelSlow16m
  1644.         inc        dl
  1645.         jmp     @@DonePixelLo
  1646.  
  1647. ;****************************************************************************
  1648. ;
  1649. ; Routine for dy > dx (slope > 1)
  1650. ;                        FS:_BX -> video buffer
  1651. ;                        _CX = # pixels to draw
  1652. ;                        _DX = Bank number for first pixel
  1653. ;                        _DI = decision variable
  1654. ;                        EIncr    - East pixel increment
  1655. ;                        NEIncr    - North East pixel increment
  1656. ;
  1657. ;****************************************************************************
  1658.  
  1659. @@HiSlopeLine:
  1660.         mov        ax,[USHORT color]        ; AL := pixel value to fill
  1661.         mov        dh,[BYTE color+2]    ; DH := current bank number
  1662.  
  1663. @@LoopHi:
  1664.         cmp        dl,[BYTE _curBank]
  1665.         je        @@SetPixelHi
  1666.  
  1667.         push    _ax                    ; Save color value
  1668.         mov        al,dl                ; AL := new bank number
  1669.         call    setBank                ; Program this bank
  1670.         pop        _ax                    ; Restore color value
  1671.  
  1672. @@SetPixelHi:
  1673.         cmp        bx,0FFFEh
  1674.         jae        @@BankSwitchHi
  1675.  
  1676. @@SetHi:
  1677.         mov        [fs:_bx],ax            ; Set pixel value in buffer
  1678.         mov        [fs:_bx+2],dh
  1679.  
  1680. @@DonePixelHi:
  1681.         add        bx,[USHORT VertInc]    ; increment y
  1682.         adc        dl,[BYTE VertInc+2]    ; Adjust bank number
  1683.         or        _di,_di                ; Test sign of d
  1684.         jns        @@HiPosDi            ; Jump if d >= 0
  1685.  
  1686.         add        _di,[EIncr]            ; d := d + EIncr
  1687.         loop    @@LoopHi            ; Loop for remaining pixels
  1688.         jmp        @@Exit                ; We are all done
  1689.  
  1690. @@HiPosDi:
  1691.         add        _di,[NEIncr]        ; d := d + NEIncr
  1692.         add        bx,3                ; Increment x
  1693.         adc        dl,0                ; Adjust bank number
  1694.         loop    @@LoopHi            ; Loop for remaining pixels
  1695.         jmp        @@Exit
  1696.  
  1697. @@BankSwitchHi:
  1698.         call    DrawPixelSlow16m
  1699.         sub        bx,3
  1700.         jmp     @@DonePixelHi
  1701.  
  1702. @@Exit:
  1703.         leave_c
  1704.         ret
  1705.  
  1706. procend        __line16m
  1707.  
  1708. ;----------------------------------------------------------------------------
  1709. ; void _line4G(int x1,int y1,int x2,int y2, long color)
  1710. ;----------------------------------------------------------------------------
  1711. ; Routine draws a line in native VGA graphics modes.
  1712. ;
  1713. ; Differentiates between horizontal, vertical and sloping lines. Horizontal
  1714. ; and vertical lines are special cases and can be drawn extremely quickly.
  1715. ; The sloping lines are drawn using the Midpoint line algorithm.
  1716. ;
  1717. ; Entry:        x1        - X1 coordinate of line to draw
  1718. ;                y1        - Y1 coordinate of line to draw
  1719. ;                x2        - X2 coordinate of line to draw
  1720. ;                y2        - Y2 coordinate of line to draw
  1721. ;                color    - color to draw the line in
  1722. ;
  1723. ;----------------------------------------------------------------------------
  1724. procstart    __line4G
  1725.  
  1726.         ARG        x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
  1727.         LOCAL    Routine:NCPTR, VertInc:ULONG, EIncr:UINT,             \
  1728.                 NEIncr:UINT = LocalSize
  1729.  
  1730.         enter_c    LocalSize
  1731.         push    eax
  1732.         cld
  1733.  
  1734.         mov        si,[_bytesperline]    ; Increment for video buffer
  1735.         mov        [USHORT VertInc+2],0    ; Zero out sign for vertical increment
  1736.  
  1737.         mov        _ax,[x2]
  1738.         sub        _ax,[x1]            ; _AX := X2 - X1
  1739.  
  1740. ; Force X1 < X2
  1741.  
  1742.         jns        @@X2Greater            ; Jump if X2 > X1
  1743.         neg        _ax                    ; _AX := X1 - X2
  1744.  
  1745.         mov        _bx,[x2]            ; Exchange X1 and X2
  1746.         xchg    _bx,[x1]
  1747.         mov        [x2],_bx
  1748.  
  1749.         mov        _bx,[y2]            ; Exchange Y1 and Y2
  1750.         xchg    _bx,[y1]
  1751.         mov        [y2],_bx
  1752.  
  1753. ; calcluate dy = ABS(Y2-Y1)
  1754.  
  1755. @@X2Greater:
  1756.         mov        _bx,[y2]
  1757.         sub        _bx,[y1]            ; _BX := Y2 - Y1
  1758.         jns        @@Y2Greater            ; Jump if slope is positive
  1759.  
  1760.         neg        _bx                    ; _BX := Y1 - Y2
  1761.         neg        si                    ; negative increment for buffer
  1762.         mov        [USHORT VertInc+2],0FFFFh    ; ensure vert increment is negative
  1763.  
  1764. ; select appropriate routine for slope of line
  1765.  
  1766. @@Y2Greater:
  1767.         mov        [USHORT VertInc],si    ; save increment
  1768.         mov        [Routine],offset @@LoSlopeLine
  1769.         cmp        _bx,_ax
  1770.         jle        @@LoSlope            ; Jump if dy <= dx (Slope <= 1)
  1771.         mov        [Routine],offset @@HiSlopeLine
  1772.         xchg    _bx,_ax                ; exchange dy and dx
  1773.  
  1774. ; calculate initial decision variable and increments
  1775.  
  1776. @@LoSlope:
  1777.         shl        _bx,1                ; _BX := 2 * dy
  1778.         mov        [EIncr],_bx            ; EIncr := 2 * dy
  1779.         sub        _bx,_ax                ; d = 2 * dy - dx
  1780.         mov        _di,_bx                ; _DI := initial decision variable
  1781.         sub        _bx,_ax
  1782.         mov        [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)
  1783.  
  1784. ; calculate first pixel address
  1785.  
  1786.         push    _ax                    ; preserve dx
  1787.         mov        _ax,[y1]
  1788.         mov        _bx,[x1]
  1789.         call    PixelAddr4G            ; FS:_BX -> buffer
  1790.  
  1791.         pop        _cx                    ; Restore dx
  1792.         inc        _cx                    ; _CX := # pixels to draw
  1793.  
  1794.         jmp        [Routine]            ; jump to appropriate routine
  1795.  
  1796. ;****************************************************************************
  1797. ;
  1798. ; Routine for dy <= dx (slope <= 1)
  1799. ;                        ES:_BX -> video buffer
  1800. ;                        _CX = # pixels to draw
  1801. ;                        _DX = Bank number for first pixel
  1802. ;                        _DI = decision variable
  1803. ;                        EIncr    - East pixel increment
  1804. ;                        NEIncr    - North East pixel increment
  1805. ;
  1806. ;****************************************************************************
  1807.  
  1808. @@LoSlopeLine:
  1809.         mov        eax,[color]            ; EAX := pixel value to fill
  1810.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1811.  
  1812. @@LoopLo:
  1813.         cmp        dl,dh
  1814.         je        @@SetLo
  1815.  
  1816.         push    _ax                    ; Save color value
  1817.         mov        al,dl                ; AL := new bank number
  1818.         call    setBank                ; Program this bank
  1819.         mov        dh,dl                ; DH := current bank number
  1820.         pop        _ax                    ; Restore color value
  1821.  
  1822. @@SetLo:
  1823.         mov        [fs:_bx],eax        ; Set pixel value in buffer
  1824.         add        bx,4                ; Increment x coordinate
  1825.         adc        dl,0                ; Adjust bank number
  1826.         or        _di,_di                ; Test sign of d
  1827.         jns        @@LoPosDi            ; Jump if d >= 0
  1828.  
  1829.         add        _di,[EIncr]            ; d := d + EIncr
  1830.         loop    @@LoopLo            ; Loop for remaining pixels
  1831.         jmp        @@Exit                ; We are all done
  1832.  
  1833. @@LoPosDi:
  1834.         add        _di,[NEIncr]        ; d := d + NEIncr
  1835.         add        bx,[USHORT VertInc]    ; increment y
  1836.         adc        dl,[BYTE VertInc+2]    ; adjust page number
  1837.         loop    @@LoopLo            ; Loop for remaining pixels
  1838.         jmp        @@Exit                ; We are all done
  1839.  
  1840. ;****************************************************************************
  1841. ;
  1842. ; Routine for dy > dx (slope > 1)
  1843. ;                        ES:_BX -> video buffer
  1844. ;                        _CX = # pixels to draw
  1845. ;                        _DX = Bank number for first pixel
  1846. ;                        _DI = decision variable
  1847. ;                        EIncr    - East pixel increment
  1848. ;                        NEIncr    - North East pixel increment
  1849. ;
  1850. ;****************************************************************************
  1851.  
  1852. @@HiSlopeLine:
  1853.         mov        eax,[color]            ; EAX := pixel value to fill
  1854.         mov        dh,[BYTE _curBank]    ; DH := current bank number
  1855.  
  1856. @@LoopHi:
  1857.         cmp        dh,dl
  1858.         je        @@SetHi
  1859.  
  1860.         push    _ax                    ; Save color value
  1861.         mov        al,dl                ; AL := new bank number
  1862.         call    setBank                ; Program this bank
  1863.         mov        dh,dl                ; DH := current bank number
  1864.         pop        _ax                    ; Restore color value
  1865.  
  1866. @@SetHi:
  1867.         mov        [fs:_bx],eax        ; Set pixel value in buffer
  1868.         add        bx,[USHORT VertInc]    ; increment y
  1869.         adc        dl,[BYTE VertInc+2]    ; Adjust bank number
  1870.         or        _di,_di                ; Test sign of d
  1871.         jns        @@HiPosDi            ; Jump if d >= 0
  1872.  
  1873.         add        _di,[EIncr]            ; d := d + EIncr
  1874.         loop    @@LoopHi            ; Loop for remaining pixels
  1875.         jmp        @@Exit                ; We are all done
  1876.  
  1877. @@HiPosDi:
  1878.         add        _di,[NEIncr]        ; d := d + NEIncr
  1879.         add        bx,4                ; Increment x
  1880.         adc        dl,0                ; Adjust bank number
  1881.         loop    @@LoopHi            ; Loop for remaining pixels
  1882.  
  1883. @@Exit:
  1884.         pop        eax
  1885.         leave_c
  1886.         ret
  1887.  
  1888. procend        __line4G
  1889.  
  1890. ;----------------------------------------------------------------------------
  1891. ; void setActivePage(int which)
  1892. ;----------------------------------------------------------------------------
  1893. ; Routine to set the video page for active output.
  1894. ;
  1895. ; Entry:        page    - Page number of page to use
  1896. ;
  1897. ;----------------------------------------------------------------------------
  1898. procstart   _setActivePage
  1899.  
  1900.         ARG     which:UINT
  1901.  
  1902.         enter_c    0
  1903.  
  1904. ; Calculate 18 bit address of page in video memory
  1905.  
  1906.         xor     eax,eax
  1907.         mov     _ax,[which]         ; EAX := page number
  1908.         mul     [_pagesize]         ; EDX:EAX := result
  1909.         mov     [originOffset],ax   ; Save video buffer offset
  1910.         shr     eax,16
  1911.         mov     [bankOffset],ax     ; Save video bank offset
  1912.  
  1913.         leave_c
  1914.         ret
  1915.  
  1916. procend     _setActivePage
  1917.  
  1918. ;----------------------------------------------------------------------------
  1919. ; void setVisualPage(int which)
  1920. ;----------------------------------------------------------------------------
  1921. ; Routine to set the visible video page.
  1922. ;
  1923. ; Entry:        page    - Page number of page to use
  1924. ;
  1925. ;----------------------------------------------------------------------------
  1926. procstart       _setVisualPage
  1927.  
  1928.         ARG     which:UINT
  1929.  
  1930.         enter_c    0
  1931.  
  1932.         cmp        [_maxpage],0        ; No flipping if only one page
  1933.         je        @@Exit
  1934.  
  1935. ; Calculate 18 bit address of page in video memory
  1936.  
  1937.         xor     eax,eax
  1938.         mov     _ax,[which]         ; EAX := page number
  1939.         mul     [_pagesize]         ; EAX := starting address in memory
  1940.         mov     edx,eax
  1941.         shr     edx,16              ; DX:AX := starting address in memory
  1942.  
  1943.         cmp     [_extendedflipping],0
  1944.         je      @@VGAFlip           ; We have no extended page flipping
  1945.  
  1946.         div     [_bytesperline]     ; AX := starting scanline,
  1947.                                     ; DX := starting byte
  1948.         mov     cx,dx
  1949.         cmp     [USHORT _maxcolor],0Fh
  1950.         je      @@16Color
  1951.         cmp     [USHORT _maxcolor],0FFh
  1952.         je      @@SetIt
  1953.         cmp     [USHORT _maxcolor+2],0FFh
  1954.         je      @@16MColor
  1955.  
  1956.         shr     cx,1                ; CX := starting pixel in buffer
  1957.         jmp     @@SetIt
  1958.  
  1959. @@16Color:
  1960.         shl     cx,3                ; CX := starting pixel in buffer
  1961.         jmp     @@SetIt
  1962.  
  1963. @@16MColor:
  1964.         mov        bx,ax                ; Preserve AX
  1965.         xor     dx,dx
  1966.         mov     ax,cx
  1967.         mov     cx,3
  1968.         div     cx
  1969.         mov     cx,ax               ; CX := starting pixel in buffer
  1970.         mov        ax,bx                ; Restore AX
  1971.  
  1972. @@SetIt:
  1973.         mov     bx,ax               ; BX := starting scanline in buffer
  1974.  
  1975.         mov     _ax,04F07h
  1976.         mov     _dx,_bx             ; DX := starting scanline number
  1977.         xor     _bx,_bx             ; BX := 0 - set display start
  1978.         int     10h                 ; Set the display start address
  1979.         jmp     @@Exit
  1980.  
  1981. @@VGAFlip:
  1982.         mov     bx,ax               ; BX := bottom 16 bits of address
  1983.  
  1984. ; Wait for display enable to be active (active low), to be sure that
  1985. ; both halves of the start address will take place in one frame. We
  1986. ; preload a few values here to save time after the DE has been
  1987. ; detected.
  1988.  
  1989.         mov     cl,0Ch              ; CL := Start Address High register
  1990.         mov     ch,bh               ; CH := high byte of new address
  1991.         mov     bh,bl               ; BH := low byte of new address
  1992.         mov     bl,0Dh              ; BL := Start Address Low register
  1993.         mov     dx,03DAh            ; DX := video status port
  1994.  
  1995. @@WaitDEVGA:
  1996.         in      al,dx
  1997.         test    al,1
  1998.         jnz     @@WaitDEVGA         ; Wait for Display Enable
  1999.  
  2000.         cli
  2001.         mov     dx,03D4h            ; DX := CRTC I/O port (3D4h)
  2002.         mov     ax,bx
  2003.         out     dx,ax
  2004.         mov     ax,cx
  2005.         out     dx,ax
  2006.         sti
  2007.  
  2008. ; Now wait for the start of the vertical sync, to ensure that the old
  2009. ; page will be invisible before anything is drawn on it.
  2010.  
  2011.         mov     dx,03DAh            ; DX := video status port
  2012. @@WaitStartVert:
  2013.         in      al,dx               ; Wait for start of vertical retrace
  2014.         test    al,8
  2015.         jz      @@WaitStartVert
  2016.  
  2017. @@Exit:
  2018.         leave_c
  2019.         ret
  2020.  
  2021. procend     _setVisualPage
  2022.  
  2023. ;----------------------------------------------------------------------------
  2024. ; setBank   Sets the read/write bank from assembly language
  2025. ;----------------------------------------------------------------------------
  2026. ;
  2027. ; Entry:        AL  - New read/write bank number
  2028. ;
  2029. ; Exit:         AL  - New read/write bank number
  2030. ;
  2031. ; Registers:    All preserved!
  2032. ;
  2033. ; Note that some VESA BIOSes and TSR's set the first window to be
  2034. ; write only and the second window to be read only, so we need to set both
  2035. ; windows for most common operations to the same value. The Universal
  2036. ; VESA VBE sets both the read and write banks to the same value for
  2037. ; Window A, and changed the read bank only for Window B, hence the second
  2038. ; call is _not_ required when the Universal VESA VBE is installed. You can
  2039. ; determine what the window does by looking at the WindowAAttributes in
  2040. ; the SuperVGAInfo block returned by function 00h. You could use this
  2041. ; information to optimise bank switching when using faster VBE's like
  2042. ; the Universal VESA VBE (but I have no bothered to do that here).
  2043. ;----------------------------------------------------------------------------
  2044. procstart   setBank
  2045.  
  2046.         push    _dx
  2047. ife flatmodel
  2048.         push    ds
  2049.         mov        dx,DGROUP            ; Address our data segment
  2050.         mov        ds,dx
  2051. endif
  2052.         mov     [_curBank],_ax      ; Save current write bank number
  2053.         cmp     [_writeBank],0
  2054.         je      @@VESABank
  2055.         mov        _dx,_ax             ; DX := bank number
  2056.         call    [_writeBank]        ; Call relocated version
  2057. ife flatmodel
  2058.         pop        ds
  2059. endif
  2060.         pop        _dx
  2061.         ret
  2062.  
  2063. @@VESABank:
  2064.         push    _ax
  2065.         push    _bx
  2066.         push    _cx
  2067.         mov        cl,[BYTE _bankShift]; Adjust to VESA granularity
  2068.         shl        al,cl
  2069.         push    _ax
  2070.         mov     _dx,_ax             ; DX := bank number
  2071.         xor     _bx,_bx             ; BX := select window A
  2072.         cmp        [_bankSwitch],0
  2073.         je      @@UseInt10
  2074.  
  2075.         call    [_bankSwitch]       ; Set write window
  2076.         pop     _dx
  2077.         inc     _bx
  2078.         call    [_bankSwitch]       ; Set read window
  2079.         jmp        @@Exit
  2080.  
  2081. ; Use the int 10h interface if the bankSwitch routine is NULL, which will
  2082. ; be the case in protected mode until VBE 2.0 (unless UniVBE 5.0 or above
  2083. ; is installed).
  2084.  
  2085. @@UseInt10:
  2086.         mov     _ax,04F05h
  2087.         int     10h
  2088.         pop     _dx
  2089.         inc     _bx
  2090.         mov     _ax,04F05h
  2091.         int     10h
  2092.  
  2093. @@Exit:    pop     _cx
  2094.         pop     _bx
  2095.         pop     _ax
  2096. ife flatmodel
  2097.         pop        ds
  2098. endif
  2099.         pop        _dx
  2100.         ret
  2101.  
  2102. procend     setBank
  2103.  
  2104. ;----------------------------------------------------------------------------
  2105. ; setReadBank   Sets the read bank from assembly language
  2106. ;----------------------------------------------------------------------------
  2107. ;
  2108. ; Entry:        AL  - New read bank number
  2109. ;
  2110. ; Exit:         AL  - New read bank number
  2111. ;
  2112. ; Registers:    All preserved!
  2113. ;
  2114. ;----------------------------------------------------------------------------
  2115. procstart   setReadBank
  2116.  
  2117.         push    _dx
  2118. ife flatmodel
  2119.         push    ds
  2120.         mov        dx,DGROUP            ; Address our data segment
  2121.         mov        ds,dx
  2122. endif
  2123.         mov     [_curBank],-1       ; Ensure banking will be re-loaded
  2124.         cmp     [_readBank],0
  2125.         je      @@VESABank
  2126.         mov        _dx,_ax             ; DX := bank number
  2127.         call    [_readBank]         ; Call relocated version
  2128. ife flatmodel
  2129.         pop        ds
  2130. endif
  2131.         pop        _dx
  2132.         ret
  2133.  
  2134. @@VESABank:
  2135.         push    _ax
  2136.         push    _bx
  2137.         push    _cx
  2138.         mov        cl,[BYTE _bankShift]; Adjust to VESA granularity
  2139.         shl        al,cl
  2140.         mov     _dx,_ax             ; DX := bank number
  2141.         mov     _bx,1               ; BX := select window B
  2142.         cmp        [_bankSwitch],0
  2143.         je      @@UseInt10
  2144.  
  2145.         call    [_bankSwitch]       ; Set read window
  2146.         jmp        @@Exit
  2147.  
  2148. ; Use the int 10h interface if the bankSwitch routine is NULL, which will
  2149. ; be the case in protected mode until VBE 2.0 (unless UniVBE 4.4 or above
  2150. ; is installed).
  2151.  
  2152. @@UseInt10:
  2153.         mov     _ax,04F05h
  2154.         int     10h
  2155.  
  2156. @@Exit:    pop     _cx
  2157.         pop     _bx
  2158.         pop     _ax
  2159. ife flatmodel
  2160.         pop        ds
  2161. endif
  2162.         pop        _dx
  2163.         ret
  2164.  
  2165. procend     setReadBank
  2166.  
  2167. ;----------------------------------------------------------------------------
  2168. ; void setBank(int bank)
  2169. ;----------------------------------------------------------------------------
  2170. ; Sets the new read/write bank number from C
  2171. ;----------------------------------------------------------------------------
  2172. procstart   _setBank
  2173.  
  2174.         ARG     bank:UINT
  2175.  
  2176.         push    _bp
  2177.         mov     _bp,_sp
  2178.         mov     _ax,[bank]
  2179.         call    setBank
  2180.         pop     _bp
  2181.         ret
  2182.  
  2183. procend     _setBank
  2184.  
  2185. ;----------------------------------------------------------------------------
  2186. ; void setReadBank(int bank)
  2187. ;----------------------------------------------------------------------------
  2188. ; Sets the new reading bank number from C
  2189. ;----------------------------------------------------------------------------
  2190. procstart   _setReadBank
  2191.  
  2192.         ARG     bank:UINT
  2193.  
  2194.         push    _bp
  2195.         mov     _bp,_sp
  2196.         mov     _ax,[bank]
  2197.         call    setReadBank
  2198.         pop     _bp
  2199.         ret
  2200.  
  2201. procend     _setReadBank
  2202.  
  2203. endcodeseg    svga
  2204.  
  2205.         END
  2206.